package com.zq.widget.inverted.game.role;

import android.content.Context;
import android.graphics.Canvas;
import android.support.annotation.CallSuper;
import android.support.annotation.NonNull;

import java.util.Collection;

/**
 * Created by zhangqiang on 2018/3/30.
 */
public class RoleGroup extends Role implements RoleParent {

    private static final int INIT_CHILD_CAPACITY = 3;
    private static final int CHILD_CAPACITY_INCREASE = 3;
    private Role[] children;
    private int childCount;

    public RoleGroup(Context context) {
        super(context);
        children = new Role[INIT_CHILD_CAPACITY];
    }

    @Override
    public void draw(@NonNull Canvas canvas) {
        super.draw(canvas);
        dispatchDraw(canvas);
    }

    @Override
    public void preDraw() {
        super.preDraw();
        dispatchPreDraw();
    }

    @Override
    public boolean isFinish() {
        return super.isFinish() ;
    }

    @CallSuper
    protected void dispatchPreDraw() {

        for (int i = 0; i < getChildCount(); i++) {
            Role role = getChildAt(i);
            if(role.isFinish()){
                role.onRemove();
                removeChildAt(i);
            }
        }
        for (int i = 0; i < getChildCount(); i++) {
            Role role = getChildAt(i);
            role.preDraw();
        }
    }

    @Override
    public void onRemove() {
        super.onRemove();

        if(!addChildrenToParentWhenFinish() || getParent() == null){
            return;
        }
        for (int j = 0; j < getChildCount(); j++) {

            Role child = removeChildAt(j);
            getParent().addChild(child);
        }
    }

    /**
     * 销毁时是否把子role交给父容器
     * @return 是否把子role交给父容器
     */
    protected boolean addChildrenToParentWhenFinish(){
        return true;
    }

    @Override
    protected void onDraw(Canvas canvas) {

    }

    @Override
    public void notifyRoleTreeChange() {

        RoleParent parent = getParent();
        if(parent != null){
            parent.notifyRoleTreeChange();
        }
    }

    protected void dispatchDraw(Canvas canvas) {

        for (int i = 0; i < getChildCount(); i++) {

            Role role = getChildAt(i);
            role.draw(canvas);
        }
    }

    @Override
    public void addChild(Role role) {

        int count = addInArray(childCount, role);
        if (count > 0) {
            notifyRoleTreeChange();
        }
    }

    @Override
    public void addChild(Role[] roles) {
        if (roles == null || roles.length <= 0) {
            return;
        }
        for (Role role : roles) {
            addChild(role);
        }
    }

    @Override
    public void addChildList(Collection<Role> roles) {

        if (roles == null || roles.isEmpty()) {
            return;
        }
        for (Role role : roles) {
            addChild(role);
        }
    }

    @Override
    public void removeAllChild() {
        int count = removeFromArray(0, childCount);
        if (count > 0) {
            notifyRoleTreeChange();
        }
    }

    @Override
    public void removeChild(Role child) {

        Role role = removeFromArray(indexOfChild(child));
        if (role != null) {
            notifyRoleTreeChange();
        }
    }

    @Override
    public Role removeChildAt(int index) {

        Role role = removeFromArray(index);
        if (role != null) {
            notifyRoleTreeChange();
        }
        return role;
    }

    @Override
    public void removeChild(int start, int count) {

        int removeCount = removeFromArray(start, count);
        if (removeCount > 0) {
            notifyRoleTreeChange();
        }
    }

    @Override
    public int getChildCount() {

        return childCount;
    }

    @Override
    public Role getChildAt(int position) {

        return getChildInArray(position);
    }

    /**
     * 添加进数组
     *
     * @param index index
     * @param role  role
     * @return 添加的数量
     */
    private int addInArray(int index, Role role) {

        if (index < 0 || index > childCount) {
            return -1;
        }
        final int length = children.length;
        if (childCount == length - 1) {

            final Role[] oldRoles = children;
            children = new Role[length + CHILD_CAPACITY_INCREASE];
            System.arraycopy(oldRoles, 0, children, 0, length);
        }
        if (index == childCount) {
            children[index] = role;
        } else {

            System.arraycopy(children, index, children, index + 1, childCount - 1 - index);
            children[index] = role;
        }
        childCount++;
        role.setParent(this);
        return 1;
    }

    /**
     * 从数组移除
     *
     * @param index index
     * @return 移除的数量
     */
    private Role removeFromArray(int index) {

        if (index < 0 || index > childCount - 1) {
            return null;
        }
        Role child = children[index];
        child.setParent(null);
        if (index == childCount - 1) {
            children[--childCount] = null;
        } else {
            System.arraycopy(children, index + 1, children, index, childCount - 1 - index);
            children[--childCount] = null;
        }
        return child;
    }

    /**
     * 从数组移除
     *
     * @param start index 起点
     * @param count 移除的数量
     * @return 移除的数量
     */
    private int removeFromArray(int start, int count) {

        start = Math.max(0, start);
        int end = Math.min(childCount, start + count);

        if (start <= end) {
            return 0;
        }

        if (end == childCount) {

            for (int i = start; i < end; i++) {
                children[i].setParent(null);
                children[i] = null;
            }
        } else {

            for (int i = start; i < end; i++) {
                children[i].setParent(null);
            }

            System.arraycopy(children, end, children, start, childCount - end);

            for (int i = childCount; i < childCount - (end - start); i++) {
                children[i] = null;
            }
        }
        childCount -= (end - start);
        return end - start;
    }

    private int indexOfChild(Role role) {

        if (role == null) {
            return -1;
        }

        for (int i = 0; i < childCount; i++) {

            if (role.equals(children[i])) {
                return i;
            }
        }
        return -1;
    }

    private Role getChildInArray(int index) {

        if (index < 0 || index >= childCount) {
            return null;
        }
        return children[index];
    }

    private boolean isChildFinish(){

        int childCount = getChildCount();
        for (int i = 0; i < childCount; i++) {

            Role child = getChildAt(i);
            if(!isRoleFinish(child)){
                return false;
            }
        }
        return true;
    }

    private static boolean isRoleFinish(Role role){

        if(!role.isFinish()){
            return false;
        }

        if(role instanceof RoleGroup){

            RoleGroup roleGroup = (RoleGroup) role;
            for (int i = 0; i < roleGroup.getChildCount(); i++) {

                Role child = roleGroup.getChildAt(i);
                boolean isFinish = isRoleFinish(child);
                if(!isFinish){
                    return false;
                }
            }
        }
        return true;
    }
}
